package csu.web.credit_bank.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import csu.web.credit_bank.mapper.ResourceMapper;
import csu.web.credit_bank.pojo.*;
import csu.web.credit_bank.pojo.vo.ResourceVO;
import csu.web.credit_bank.service.*;
import csu.web.credit_bank.utils.AliOssUtil;
import csu.web.credit_bank.utils.UUIDManager;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class ResourceServiceImpl extends ServiceImpl<ResourceMapper, Resource> implements ResourceService {

    @Autowired
    private AliOssUtil aliOssUtil;

    // 2. 【新增】注入 UUIDManager
    @Autowired
    private UUIDManager uuidManager;

    @Autowired
    private ResourceRecommendationsService recommendationsService; // 注入推荐服务

    @Autowired
    private UsersService usersService;
    @Autowired
    private StudentsService studentsService;
    @Autowired
    private TeachersService teachersService;

    // 根据您的表结构，定义类别常量
    private static final int CATEGORY_PDF = 0;
    private static final int CATEGORY_VIDEO = 1;
    private static final int CATEGORY_OTHER = 2;

    // 定义允许上传的文件MIME类型集合
    private static final Set<String> ALLOWED_TYPES = new HashSet<>(Arrays.asList(
            // 图片
            "image/jpeg", "image/png", "image/gif",
            // 视频
            "video/mp4", "video/quicktime",
            // PPT
            "application/vnd.ms-powerpoint", "application/vnd.openxmlformats-officedocument.presentationml.presentation",
            // PDF
            "application/pdf",
            // Word
            "application/msword", "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
            // Zip
            "application/zip",
            // Excel
            "application/vnd.ms-excel", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
            //文本文件
            "text/plain", "application/octet-stream"
    ));

    @Override
    @Transactional
    public Resource createResourceWithUpload(MultipartFile file, MultipartFile coverImage, Resource resource) {
        if (resource == null) {
            throw new IllegalArgumentException("资源参数不能为空");
        }
        if (file == null || file.isEmpty()) {
            throw new IllegalArgumentException("上传的资源文件不能为空");
        }
        String fileType = file.getContentType();
        if (!ALLOWED_TYPES.contains(fileType)) {
            throw new IllegalArgumentException("不支持的资源文件类型: " + fileType);
        }String fileUrl = null;
        try {
            fileUrl = aliOssUtil.upload(file.getInputStream(), file.getOriginalFilename());
            if (!StringUtils.hasText(fileUrl)) {
                throw new RuntimeException("资源文件上传到OSS失败");
            }
        } catch (IOException e) {
            throw new RuntimeException("读取资源上传文件失败", e);
        }String coverImageUrl = null;
        if (coverImage != null && !coverImage.isEmpty()) {
            // 可选：增加对封面图片类型的校验
            String coverType = coverImage.getContentType();
            if (coverType == null || !coverType.startsWith("image/")) {
                // 如果上传失败，需要删除之前已经上传的资源文件
                aliOssUtil.delete(fileUrl);
                throw new IllegalArgumentException("封面文件必须是图片类型");
            }
            try {
                coverImageUrl = aliOssUtil.upload(coverImage.getInputStream(), coverImage.getOriginalFilename());
                if (!StringUtils.hasText(coverImageUrl)) {
                    // 如果上传失败，需要删除之前已经上传的资源文件
                    aliOssUtil.delete(fileUrl);
                    throw new RuntimeException("封面图片上传到OSS失败");
                }
            } catch (IOException e) {
                // 如果读取失败，需要删除之前已经上传的资源文件
                aliOssUtil.delete(fileUrl);
                throw new RuntimeException("读取封面上传文件失败", e);
            }
        }else {
            coverImageUrl = "https://creditbank.oss-cn-chengdu.aliyuncs.com/2025/07/02/d608cb75-1f1c-48d1-819c-03152564aa22.png";
        }
        String resourceId = uuidManager.getUUID();
        if (resourceId == null) {
            throw new RuntimeException("ID池已空，无法分配新ID，资源创建失败");
        }resource.setId(resourceId);
        resource.setLocation(fileUrl);
        if (coverImageUrl != null) {
            resource.setCoverImage(coverImageUrl);
        }if ("application/pdf".equals(fileType)) {
            resource.setCategory(CATEGORY_PDF);
        } else if (fileType.startsWith("video/")) {
            resource.setCategory(CATEGORY_VIDEO);
        } else {
            resource.setCategory(CATEGORY_OTHER);
        }boolean success = this.save(resource);
        if (!success) {
            aliOssUtil.delete(fileUrl);
            if (coverImageUrl != null) {
                aliOssUtil.delete(coverImageUrl); // 【新增】删除封面
            }
            throw new RuntimeException("资源信息保存到数据库失败");
        }return resource;
    }
    @Override
    @Transactional
    public boolean deleteResource(String id) {
        Resource resource = this.getById(id);
        if (resource == null) {
            return true;
        }boolean removed = this.removeById(id);
        if (!removed) {
            return false;
        }if (StringUtils.hasText(resource.getLocation())) {
            try {
                aliOssUtil.delete(resource.getLocation());
            } catch (Exception e) {
                log.error("OSS file deletion failed for URL: {}", resource.getLocation(), e);
            }
        }if (StringUtils.hasText(resource.getCoverImage())) {
            try {
                aliOssUtil.delete(resource.getCoverImage());
            } catch (Exception e) {
                log.error("OSS cover image deletion failed for URL: {}", resource.getCoverImage(), e);
            }
        }return true;
    }
    @Override
    public IPage<ResourceVO> searchResources(Page<Resource> page, String major, Integer category, Integer difficulty, String keyword, String sort) {
        QueryWrapper<Resource> queryWrapper = new QueryWrapper<>();
        if (StringUtils.hasText(major)) {
            queryWrapper.eq("r.major", major);
        }
        if (category != null) {
            queryWrapper.eq("r.category", category);
        }
        if (difficulty != null) {
            queryWrapper.eq("r.difficulty", difficulty);
        }
        if (StringUtils.hasText(keyword)) {
            queryWrapper.like("r.title", keyword);
        }
        if (StringUtils.hasText(sort)) {
            String[] sortParts = sort.split(",");
            if (sortParts.length == 2) {
                String sortField = sortParts[0];
                String sortOrder = sortParts[1];
                List<String> allowedSortFields = Arrays.asList("id", "credit", "difficulty");
                if (allowedSortFields.contains(sortField)) {
                    if ("desc".equalsIgnoreCase(sortOrder)) {
                        queryWrapper.orderByDesc("r." + sortField);
                    } else {
                        queryWrapper.orderByAsc("r." + sortField);
                    }
                }
            }
        } else {
            queryWrapper.orderByDesc("r.id");
        }
        Page<ResourceVO> dtoPage = new Page<>(page.getCurrent(), page.getSize());
        IPage<ResourceVO> resultPage = baseMapper.selectResourcePageWithUsername(dtoPage, queryWrapper);
        populatePublisherAvatars(resultPage);
        if (resultPage != null && resultPage.getRecords() != null && !resultPage.getRecords().isEmpty()) {
            Set<String> publisherIds = resultPage.getRecords().stream()
                    .map(ResourceVO::getPublisherId)
                    .filter(StringUtils::hasText)
                    .collect(Collectors.toSet());

            if (!publisherIds.isEmpty()) {
                List<User> users = usersService.listByIds(publisherIds);
                Map<String, User> userMap = users.stream()
                        .collect(Collectors.toMap(User::getId, user -> user));
                Set<String> studentIds = new HashSet<>();
                Set<String> teacherIds = new HashSet<>();
                for (String pId : publisherIds) {
                    User user = userMap.get(pId);
                    if (user != null) {
                        if (user.getUserType() != null) {
                            if (user.getUserType() == 0) {
                                studentIds.add(pId);
                            } else if (user.getUserType() == 1) {
                                teacherIds.add(pId);
                            }
                        }
                    }
                }

                Map<String, String> avatarMap = new HashMap<>();
                if (!studentIds.isEmpty()) {
                    List<Students> students = studentsService.listByIds(studentIds);
                    students.forEach(s -> avatarMap.put(s.getUserId(), s.getAvatar()));
                }
                if (!teacherIds.isEmpty()) {
                    List<Teachers> teachers = teachersService.listByIds(teacherIds);
                    teachers.forEach(t -> avatarMap.put(t.getUserId(), t.getAvatar()));
                }

                for (ResourceVO resourceVO : resultPage.getRecords()) {
                    String publisherId = resourceVO.getPublisherId();
                    if (StringUtils.hasText(publisherId) && avatarMap.containsKey(publisherId)) {
                        resourceVO.setPublisherAvatar(avatarMap.get(publisherId));
                    }
                }
            }
        }

        return resultPage;
    }
    @Override
    @Transactional
    public Resource updateResourceFile(String id, MultipartFile file) {
        if (file == null || file.isEmpty()) {
            throw new IllegalArgumentException("上传文件不能为空");
        }
        Resource resource = this.getById(id);
        if (resource == null) {
            throw new NoSuchElementException("ID为 " + id + " 的资源不存在");
        }String oldFileUrl = resource.getLocation();
        if (StringUtils.hasText(oldFileUrl)) {
            try {
                aliOssUtil.delete(oldFileUrl);
            } catch (Exception e) {
                log.error("删除OSS旧文件失败, URL: {}", oldFileUrl, e);
            }
        }String newFileUrl;
        try {
            newFileUrl = aliOssUtil.upload(file.getInputStream(), file.getOriginalFilename());
            if (!StringUtils.hasText(newFileUrl)) {
                throw new RuntimeException("文件上传到OSS失败");
            }
        } catch (IOException e) {
            throw new RuntimeException("读取上传文件失败", e);
        }resource.setLocation(newFileUrl);
        boolean success = this.updateById(resource);
        if (!success) {
            throw new RuntimeException("更新资源文件位置信息失败");
        }return resource;
    }
    @Override
    public IPage<ResourceVO> getPersonalizedRecommendations(String userId, Page<ResourceVO> page) {
        List<ResourceRecommendation> userRecommendations = recommendationsService.getRecommendationsByUserId(userId);
        if (userRecommendations == null || userRecommendations.isEmpty()) {
            return new Page<>(); // 返回空分页
        }
        String favoriteMajor = userRecommendations.stream()
                .max(Comparator.comparing(ResourceRecommendation::getViewCount))
                .map(ResourceRecommendation::getMajor)
                .orElse(null);
        if (!StringUtils.hasText(favoriteMajor)) {
            return new Page<>();
        }
        QueryWrapper<Resource> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("r.major", favoriteMajor).orderByDesc("r.id"); // 注意字段要带别名'r.'
        return baseMapper.selectResourcePageWithUsername(page, queryWrapper);
    }
    @Override
    @Transactional
    public Resource createResourceRecord(Resource resource) {
        if (resource == null) {
            throw new IllegalArgumentException("资源对象不能为空");
        }String resourceId = uuidManager.getUUID();
        if (resourceId == null) {
            throw new RuntimeException("ID池已空，无法分配新ID");
        }resource.setId(resourceId);
        if (!this.save(resource)) {
            throw new RuntimeException("资源信息保存到数据库失败");
        }return resource;
    }

    @Override
    public ResourceVO getResourceVOById(String id) {
        ResourceVO resourceVO = baseMapper.selectResourceWithUsernameById(id);
        if (resourceVO != null && StringUtils.hasText(resourceVO.getPublisherId())) {
            User user = usersService.getById(resourceVO.getPublisherId());
            if (user != null && user.getUserType() != null) {
                if (user.getUserType() == 0) {

                    Students student = studentsService.getById(user.getId());
                    if (student != null) {
                        resourceVO.setPublisherAvatar(student.getAvatar());
                    }
                } else if (user.getUserType() == 1) {
                    Teachers teacher = teachersService.getById(user.getId());
                    if (teacher != null) {
                        resourceVO.setPublisherAvatar(teacher.getAvatar());
                    }
                }
            }
        }
        return resourceVO;
    }
    @Override
    public IPage<ResourceVO> searchResources(Page<Resource> page, QueryWrapper<Resource> queryWrapper) {
        Page<ResourceVO> dtoPage = new Page<>(page.getCurrent(), page.getSize());
        IPage<ResourceVO> resultPage = baseMapper.selectResourcePageWithUsername(dtoPage, queryWrapper);
        populatePublisherAvatars(resultPage);
        return resultPage;
    }

    private void populatePublisherAvatars(IPage<ResourceVO> resourcePage) {
        if (resourcePage == null || resourcePage.getRecords() == null || resourcePage.getRecords().isEmpty()) {
            return;
        }

        Set<String> publisherIds = resourcePage.getRecords().stream()
                .map(ResourceVO::getPublisherId)
                .filter(StringUtils::hasText)
                .collect(Collectors.toSet());

        if (publisherIds.isEmpty()) {
            return;
        }
        List<User> users = usersService.listByIds(publisherIds);
        Map<String, User> userMap = users.stream()
                .collect(Collectors.toMap(User::getId, user -> user));

        Set<String> studentIds = new HashSet<>();
        Set<String> teacherIds = new HashSet<>();
        for (String pId : publisherIds) {
            User user = userMap.get(pId);
            if (user != null && user.getUserType() != null) {
                if (user.getUserType() == 0) {
                    studentIds.add(pId);
                } else if (user.getUserType() == 1) {
                    teacherIds.add(pId);
                }
            }
        }
        Map<String, String> avatarMap = new HashMap<>();
        if (!studentIds.isEmpty()) {
            List<Students> students = studentsService.listByIds(studentIds);
            students.forEach(s -> avatarMap.put(s.getUserId(), s.getAvatar()));
        }
        if (!teacherIds.isEmpty()) {
            List<Teachers> teachers = teachersService.listByIds(teacherIds);
            teachers.forEach(t -> avatarMap.put(t.getUserId(), t.getAvatar()));
        }
        for (ResourceVO resourceVO : resourcePage.getRecords()) {
            String publisherId = resourceVO.getPublisherId();
            if (StringUtils.hasText(publisherId) && avatarMap.containsKey(publisherId)) {
                resourceVO.setPublisherAvatar(avatarMap.get(publisherId));
            }
        }
    }
}